/**
 * Copyright (c) 2011-2017, James Zhan 詹波 (jfinal@126.com).
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.jfinal.kit;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

/**
 * 反射工具类
 */
public class ReflectKit {

	private static final String TYPE_CLASS_NAME_PREFIX = "class ";
	private static final String TYPE_INTERFACE_NAME_PREFIX = "interface ";

	public static Object newInstance(Class<?> clazz) {
		try {
			return clazz.newInstance();
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	public static <T> T newInstance(String className) {
		try {
			Class objClass = Class.forName(className);
			return (T) objClass.newInstance();
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	/**
	 * Returns the {@code Class} object associated with the given {@link Type}
	 * depending on its fully qualified name.
	 *
	 * @param type the {@code Type} whose {@code Class} is needed.
	 * @return the {@code Class} object for the class with the specified name.
	 * @throws ClassNotFoundException if the class cannot be located.
	 * @see {@link ReflectKit#getClassName(Type)}
	 */
	public static Class<?> getClass(Type type)
			throws ClassNotFoundException {
		String className = getClassName(type);
		if (className == null || className.isEmpty()) {
			return null;
		}
		return Class.forName(className);
	}

	/**
	 * {@link Type#toString()} value is the fully qualified class name prefixed
	 * with {@link ReflectKit#TYPE_CLASS_NAME_PREFIX}. This method will substring it, for it to be eligible
	 * for {@link Class#forName(String)}.
	 *
	 * @param type the {@code Type} value whose class name is needed.
	 * @return {@code String} class name of the invoked {@code type}.
	 * @see {@link ReflectKit#getClass()}
	 */
	public static String getClassName(Type type) {
		if (type == null) {
			return "";
		}
		String className = type.toString();
		if (className.startsWith(TYPE_CLASS_NAME_PREFIX)) {
			className = className.substring(TYPE_CLASS_NAME_PREFIX.length());
		} else if (className.startsWith(TYPE_INTERFACE_NAME_PREFIX)) {
			className = className.substring(TYPE_INTERFACE_NAME_PREFIX.length());
		}
		return className;
	}

	/**
	 * Returns an array of {@code Type} objects representing the actual type
	 * arguments to this object.
	 * If the returned value is null, then this object represents a non-parameterized
	 * object.
	 *
	 * @param object the {@code object} whose type arguments are needed.
	 * @return an array of {@code Type} objects representing the actual type
	 * arguments to this object.
	 * @see {@link Class#getGenericSuperclass()}
	 * @see {@link ParameterizedType#getActualTypeArguments()}
	 */
	public static Type[] getParameterizedTypes(Object object) {
		Type superclassType = object.getClass().getGenericSuperclass();
		if (!ParameterizedType.class.isAssignableFrom(superclassType.getClass())) {
			return null;
		}

		return ((ParameterizedType) superclassType).getActualTypeArguments();
	}
}






